package view;

import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

import modele.Square;
import modele.World;
import modele.worldAgent.Agent;

public class Render extends Applet implements Runnable {
 
	static final public float MAXX = 10000F; 
	static final public float MAXY = 7500F;
	final private int WORLDSIZE = 300;
	
	static final public int PREF_VIEWER_XSIZE = 800; // size in pixels (in x, the y is automatically deduced)
	// Viewer variables
    float viewer_scale; // Ratio from size of surface to size of viewer
    static int viewer_xsize;
    static int viewer_ysize;
    boolean alti_view;
    Image buffer_canvasimage;// Canvas for double buffering
    Graphics buffer_canvas; // Where to draw (off-screen buffer)
    Graphics viewer_canvas; // What the user actually see (on-screen buffer)
    double timeOfTheLastEvent ;
    
    
    
    private Thread update;
    
    World w;
    
    long lasttime;
    
    int screenPositionx;//the i index of the North-West square
    int screenPositiony;//the j index of the North-West square
    int squareSize;
    
	public Render(){
		squareSize = Math.max(3, PREF_VIEWER_XSIZE / WORLDSIZE);
		viewer_scale = MAXX/PREF_VIEWER_XSIZE;
		screenPositionx = 0;
	    screenPositiony = 0;
		alti_view = false;
	}
	
	public void init()
    {
		super.init();
		timeOfTheLastEvent = System.currentTimeMillis();
        
        viewer_xsize = PREF_VIEWER_XSIZE; // size in pixels
//        viewer_ysize = PREF_VIEWER_XSIZE; // The y axe is automatically computed
        viewer_ysize = (int)(MAXY/viewer_scale); // The y axe is automatically computed
        
        resize(viewer_xsize, viewer_ysize);
        buffer_canvasimage = createImage(viewer_xsize, viewer_ysize);
        buffer_canvas = buffer_canvasimage.getGraphics();
        viewer_canvas = this.getGraphics();
        this.addKeyListener(new MyKeyListener());
        this.addMouseWheelListener(new MouseWheelListener() {
			@Override
			public void mouseWheelMoved(MouseWheelEvent arg0) {
				
				squareSize-=arg0.getWheelRotation();
				squareSize = Math.max(3, squareSize);
				double localTime = System.currentTimeMillis();
				if(localTime - timeOfTheLastEvent > 100){
					paint(null);
					timeOfTheLastEvent = localTime;
				}
			}
		});
        w=new World(WORLDSIZE);
        lasttime = System.currentTimeMillis();
       
    }
	// Use very simple double buffering technique...
    /**
     * This is a very simple double buffering technique.
     * Drawing are done offscreen, in the buffer_canvasimage canvas.
     * Ones all drawings are done, we copy the whole canvas to 
     * the actual viewed canvas, viewer_canvas.
     * Thus the player will only see a very fast update of its window.
     * No flickering.
     * 
     */
    private void showbuffer()
    {
        viewer_canvas.drawImage(buffer_canvasimage, 0, 0, this);
    }

    /* 
     * Called by repaint, to paint all the offscreen surface.
     * We erase everything, then redraw each components.
     * 
     * @see java.awt.Container#paint(java.awt.Graphics)
     */
    public void paint(Graphics g)
    {
    	// 1. We erase everything
        buffer_canvas.setColor(Color.lightGray); // Background color
        buffer_canvas.fillRect(0, 0, viewer_xsize, viewer_ysize);
        

        buffer_canvas.setColor(Color.black);
        buffer_canvas.drawRect(0, 0, viewer_xsize - 1, viewer_ysize - 1);
       
//        System.out.println("size to repaint : "+w.getToRepaint().size());
//        for(Square s : w.getToRepaint()){
//    		//System.out.print(w.getMap()[i][j]+" ");
//    		if(alti_view) buffer_canvas.setColor(new Color((int)s.getPosZ(),(int)s.getPosZ(),(int)s.getPosZ()));
//    		else buffer_canvas.setColor(s.getColor());
//    		buffer_canvas.fillRect(s.getPosX()*viewer_xsize/w.getWidth(), s.getPosY()*viewer_ysize/w.getWidth(), viewer_xsize/w.getWidth(), viewer_ysize/w.getWidth());
//        }
       
        // 3. draw world
        //compute the size of a square
        int maxX = viewer_xsize / squareSize;
        int maxY = viewer_ysize / squareSize;
        for(int i = 0 ; i <= maxX ; i++  ){
        	if(i + screenPositionx < w.getWidth() && i + screenPositionx >= 0){
        		for(int j = 0 ; j <= maxY ; j++){
        			if(j + screenPositiony < w.getWidth() && j + screenPositiony >= 0){
						try{
							Square sTmp = w.getSquareMap()[i+screenPositionx][j+screenPositiony];
							if(alti_view) buffer_canvas.setColor(new Color((int)sTmp.getPosZ(),sTmp.getPosZ(),sTmp.getPosZ()));
							else buffer_canvas.setColor(sTmp.getColor());
							buffer_canvas.fillRect(i*squareSize, j*squareSize, squareSize, squareSize);
							Agent aTmp = w.getAgent(sTmp.getPosX(), sTmp.getPosY());
							if(aTmp != null ){
								buffer_canvas.setColor(aTmp.getColor());
								buffer_canvas.fillRect(i*squareSize+1, j*squareSize+1, squareSize - 2, squareSize - 2);
							}
						} catch(java.lang.IllegalArgumentException e){
							System.out.println("Alti= "+(int)w.getSquareMap()[i][j].getPosZ());
						}
	    			}
	        	}
	        }
        }
        showbuffer();
    }

    public void update(Graphics g)
    {
    	//Evolve world
    	long time = System.currentTimeMillis();
    	w.evolve();
    	time -=System.currentTimeMillis();
    	System.out.println("Temps evolve: "+time);
    	//Paint
    	time = System.currentTimeMillis();
        paint(g);
        time -=System.currentTimeMillis();
    	System.out.println("Temps Paint: "+time);
    }
    
   	
	public void windowClosing(WindowEvent e)
	{
		System.exit(1);
	}
	
	public static void main(String args[])
	{
		Frame f = new Frame();
        Render app = new Render();
        f.add("Center", app);
        f.pack();
        
        f.setSize(800, 640);
        f.setVisible(true);
        app.init();
        app.start();
	}

    public void start()
    {
        if(update == null)
        {
            update = new Thread(this);
            update.start();
        }
    }

    public void stop()
    {
        update = null;
    }
	
	@Override
	public void run() {
		do
        {
            long time = System.currentTimeMillis();
            if(time - lasttime > 200){
            	repaint();
            	lasttime = System.currentTimeMillis();
            }
        } while(true);
	}

	
	private class MyKeyListener implements KeyListener {
    	@Override
    	public void keyPressed(KeyEvent arg0) {
			System.out.println("Key pressed "+ arg0.getKeyCode());
			
			switch(arg0.getKeyCode()){
				case KeyEvent.VK_SPACE:	
					System.out.println("Changement de mode de vue");
					alti_view = !alti_view;
					break;
				case KeyEvent.VK_Q :
					System.out.println("Exit");
					System.exit(0);
					break;
				case KeyEvent.VK_DOWN :
					screenPositiony++;
					break;
				case KeyEvent.VK_UP :
					screenPositiony--;
					break;
				case KeyEvent.VK_RIGHT :
					screenPositionx++;
					break;
				case KeyEvent.VK_LEFT :
					screenPositionx--;
					break;
			}
			double localTime = System.currentTimeMillis();
			if(localTime - timeOfTheLastEvent > 100){
				paint(null);
				timeOfTheLastEvent = localTime;
			}
    	}
    	@Override
    	public void keyReleased(KeyEvent arg0) {
    		// TODO Auto-generated method stub
    		
    	}

    	@Override
    	public void keyTyped(KeyEvent arg0) {
    		
    	}

	}
	
}
